home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / lang / ThreadGroup.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  29.7 KB  |  930 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)ThreadGroup.java    1.43 98/10/01
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.lang;
  16.  
  17. import java.io.PrintStream;
  18. import sun.misc.VM;
  19.  
  20. /**
  21.  * A thread group represents a set of threads. In addition, a thread 
  22.  * group can also include other thread groups. The thread groups form 
  23.  * a tree in which every thread group except the initial thread group 
  24.  * has a parent. 
  25.  * <p>
  26.  * A thread is allowed to access information about its own thread 
  27.  * group, but not to access information about its thread group's 
  28.  * parent thread group or any other thread groups. 
  29.  *
  30.  * @author  unascribed
  31.  * @version 1.43, 10/01/98
  32.  * @since   JDK1.0
  33.  */
  34. /* The locking strategy for this code is to try to lock only one level of the
  35.  * tree wherever possible, but otherwise to lock from the bottom up.
  36.  * That is, from child thread groups to parents.
  37.  * This has the advantage of limiting the number of locks that need to be held
  38.  * and in particular avoids having to grab the lock for the root thread group,
  39.  * (or a global lock) which would be a source of contention on a 
  40.  * multi-processor system with many thread groups.
  41.  * This policy often leads to taking a snapshot of the state of a thread group
  42.  * and working off of that snapshot, rather than holding the thread group locked
  43.  * while we work on the children.
  44.  */
  45. public
  46. class ThreadGroup {
  47.     ThreadGroup parent;
  48.     String name;
  49.     int maxPriority;
  50.     boolean destroyed;
  51.     boolean daemon;
  52.     boolean vmAllowSuspension;
  53.  
  54.     int nthreads;
  55.     Thread threads[];
  56.  
  57.     int ngroups;
  58.     ThreadGroup groups[];
  59.  
  60.     /**
  61.      * Creates an empty Thread group that is not in any Thread group. 
  62.      * This method is used to create the system Thread group.
  63.      */
  64.     private ThreadGroup() {    // called from C code
  65.     this.name = "system";
  66.     this.maxPriority = Thread.MAX_PRIORITY;
  67.     }
  68.  
  69.     /**
  70.      * Constructs a new thread group. The parent of this new group is 
  71.      * the thread group of the currently running thread. 
  72.      * <p>
  73.      * The <code>checkAccess</code> method of the parent thread group is 
  74.      * called with no arguments; this may result in a security exception. 
  75.      *
  76.      * @param   name   the name of the new thread group.
  77.      * @exception  SecurityException  if the current thread cannot create a
  78.      *               thread in the specified thread group.
  79.      * @see     java.lang.ThreadGroup#checkAccess()
  80.      * @since   JDK1.0
  81.      */
  82.     public ThreadGroup(String name) {
  83.     this(Thread.currentThread().getThreadGroup(), name);
  84.     }
  85.  
  86.     /**
  87.      * Creates a new thread group. The parent of this new group is the 
  88.      * specified thread group. 
  89.      * <p>
  90.      * The <code>checkAccess</code> method of the parent thread group is 
  91.      * called with no arguments; this may result in a security exception. 
  92.      *
  93.      * @param     parent   the parent thread group.
  94.      * @param     name     the name of the new thread group.
  95.      * @exception  NullPointerException  if the thread group argument is
  96.      *               <code>null</code>.
  97.      * @exception  SecurityException  if the current thread cannot create a
  98.      *               thread in the specified thread group.
  99.      * @see     java.lang.SecurityException
  100.      * @see     java.lang.ThreadGroup#checkAccess()
  101.      * @since   JDK1.0
  102.      */
  103.     public ThreadGroup(ThreadGroup parent, String name) {
  104.     if (parent == null) {
  105.         throw new NullPointerException();
  106.     }
  107.     parent.checkAccess();
  108.     this.name = name;
  109.     this.maxPriority = parent.maxPriority;
  110.     this.daemon = parent.daemon;
  111.     this.vmAllowSuspension = parent.vmAllowSuspension;
  112.     this.parent = parent;
  113.     parent.add(this);
  114.     }
  115.  
  116.     /**
  117.      * Returns the name of this thread group.
  118.      *
  119.      * @return  the name of this thread group.
  120.      * @since   JDK1.0
  121.      */
  122.     public final String getName() {
  123.     return name;
  124.     }
  125.  
  126.     /**
  127.      * Returns the parent of this thread group.
  128.      * <p>
  129.      * First, if the parent is not <code>null</code>, the 
  130.      * <code>checkAccess</code> method of the parent thread group is 
  131.      * called with no arguments; this may result in a security exception. 
  132.      *
  133.      * @return  the parent of this thread group. The top-level thread group
  134.      *          is the only thread group whose parent is <code>null</code>.
  135.      * @exception  SecurityException  if the current thread cannot access
  136.      *               the parent thread group.
  137.      * @see        java.lang.ThreadGroup#checkAccess()
  138.      * @since   JDK1.0
  139.      */
  140.     public final ThreadGroup getParent() {
  141.     if (parent != null)
  142.         parent.checkAccess();
  143.     return parent;
  144.     }
  145.  
  146.     /**
  147.      * Returns the maximum priority of this thread group. Threads that are
  148.      * part of this group cannot have a higher priority than the maximum
  149.      * priority.
  150.      *
  151.      * @return  the maximum priority that a thread in this thread group
  152.      *          can have.
  153.      * @since   JDK1.0
  154.      */
  155.     public final int getMaxPriority() {
  156.     return maxPriority;
  157.     }
  158.  
  159.     /**
  160.      * Tests if this thread group is a daemon thread group. A 
  161.      * daemon thread group is automatically destroyed when its last 
  162.      * thread is stopped or its last thread group is destroyed. 
  163.      *
  164.      * @return  <code>true</code> if this thread group is a daemon thread group;
  165.      *          <code>false</code> otherwise.
  166.      * @since   JDK1.0
  167.      */
  168.     public final boolean isDaemon() {
  169.     return daemon;
  170.     }
  171.  
  172.     /**
  173.      * Tests if this thread group has been destroyed.
  174.      *
  175.      * @since   JDK1.1
  176.      */
  177.     public synchronized boolean isDestroyed() {
  178.     return destroyed;
  179.     }
  180.  
  181.     /**
  182.      * Changes the daemon status of this thread group.
  183.      * <p>
  184.      * First, the <code>checkAccess</code> method of this thread group is 
  185.      * called with no arguments; this may result in a security exception. 
  186.      * <p>
  187.      * A daemon thread group is automatically destroyed when its last 
  188.      * thread is stopped or its last thread group is destroyed. 
  189.      *
  190.      * @param      daemon   if <code>true</code>, marks this thread group as
  191.      *                      a daemon thread group; otherwise, marks this
  192.      *                      thread group as normal.
  193.      * @exception  SecurityException  if the current thread cannot modify
  194.      *               this thread group.
  195.      * @see        java.lang.SecurityException
  196.      * @see        java.lang.ThreadGroup#checkAccess()
  197.      * @since      JDK1.0
  198.      */
  199.     public final void setDaemon(boolean daemon) {
  200.     checkAccess();
  201.     this.daemon = daemon;
  202.     }
  203.  
  204.     /**
  205.      * Sets the maximum priority of the group. 
  206.      * <p>
  207.      * First, the <code>checkAccess</code> method of this thread group is 
  208.      * called with no arguments; this may result in a security exception. 
  209.      * <p>
  210.      * Threads in the thread group that already have a higher priority 
  211.      * are not affected. 
  212.      *
  213.      * @param      pri   the new priority of the thread group.
  214.      * @exception  SecurityException  if the current thread cannot modify
  215.      *               this thread group.
  216.      * @see        java.lang.SecurityException
  217.      * @see        java.lang.ThreadGroup#checkAccess()
  218.      * @since      JDK1.0
  219.      */
  220.     public final void setMaxPriority(int pri) {
  221.     int ngroupsSnapshot;
  222.     ThreadGroup[] groupsSnapshot;
  223.     synchronized (this) {
  224.         checkAccess();
  225.         if (pri < Thread.MIN_PRIORITY) {
  226.         maxPriority = Thread.MIN_PRIORITY;
  227.         } else if (pri < maxPriority) {
  228.         maxPriority = pri;
  229.         }
  230.         ngroupsSnapshot = ngroups;
  231.         if (groups != null) {
  232.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  233.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  234.         } else {
  235.         groupsSnapshot = null;
  236.         }
  237.     }
  238.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  239.         groupsSnapshot[i].setMaxPriority(pri);
  240.     }
  241.     }
  242.  
  243.     /**
  244.      * Tests if this thread group is either the thread group 
  245.      * argument or one of its ancestor thread groups. 
  246.      *
  247.      * @param   g   a thread group.
  248.      * @return  <code>true</code> if this thread group is the thread group
  249.      *          argument or one of its ancestor thread groups;
  250.      *          <code>false</code> otherwise.
  251.      * @since   JDK1.0
  252.      */
  253.     public final boolean parentOf(ThreadGroup g) {
  254.     for (; g != null ; g = g.parent) {
  255.         if (g == this) {
  256.         return true;
  257.         }
  258.     }
  259.     return false;
  260.     }
  261.  
  262.     /**
  263.      * Determines if the currently running thread has permission to 
  264.      * modify this thread group. 
  265.      * <p>
  266.      * If there is a security manager, its <code>checkAccess</code> method 
  267.      * is called with this thread group as its argument. This may result 
  268.      * in throwing a <code>SecurityException</code>. 
  269.      *
  270.      * @exception  SecurityException  if the current thread is not allowed to
  271.      *               access this thread group.
  272.      * @see        java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)
  273.      * @since      JDK1.0
  274.      */
  275.     public final void checkAccess() {
  276.     SecurityManager security = System.getSecurityManager();
  277.     if (security != null) {
  278.         security.checkAccess(this);
  279.     }
  280.     }
  281.  
  282.     /**
  283.      * Returns an estimate of the number of active threads in this
  284.      * thread group.
  285.      *
  286.      * @return  the number of active threads in this thread group and in any
  287.      *          other thread group that has this thread group as an ancestor.
  288.      * @since   JDK1.0
  289.      */
  290.     public int activeCount() {
  291.     int result;
  292.     // Snapshot sub-group data so we don't hold this lock
  293.     // while our children are computing.
  294.     int ngroupsSnapshot;
  295.     ThreadGroup[] groupsSnapshot;
  296.     synchronized (this) {
  297.         if (destroyed) {
  298.         return 0;
  299.         }
  300.         result = nthreads;
  301.         ngroupsSnapshot = ngroups;
  302.         if (groups != null) {
  303.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  304.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  305.         } else {
  306.         groupsSnapshot = null;
  307.         }
  308.     }
  309.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  310.         result += groupsSnapshot[i].activeCount();
  311.     }
  312.     return result;
  313.     }
  314.  
  315.     /**
  316.      * Copies into the specified array every active thread in this 
  317.      * thread group and its subgroups. 
  318.      * <p>
  319.      * First, the <code>checkAccess</code> method of this thread group is 
  320.      * called with no arguments; this may result in a security exception. 
  321.      * <p>
  322.      * An application should use the <code>activeCount</code> method to 
  323.      * get an estimate of how big the array should be. If the array is 
  324.      * too short to hold all the threads, the extra threads are silently 
  325.      * ignored. 
  326.      *
  327.      * @param   list   an array into which to place the list of threads.
  328.      * @return  the number of threads put into the array.
  329.      * @exception  SecurityException  if the current thread does not
  330.      *               have permission to enumerate this thread group.
  331.      * @see     java.lang.ThreadGroup#activeCount()
  332.      * @see     java.lang.ThreadGroup#checkAccess()
  333.      * @since   JDK1.0
  334.      */
  335.     public int enumerate(Thread list[]) {
  336.         checkAccess();
  337.     return enumerate(list, 0, true);
  338.     }
  339.  
  340.     /**
  341.      * Copies into the specified array every active thread in this 
  342.      * thread group. If the <code>recurse</code> flag is 
  343.      * <code>true</code>, references to every active thread in this 
  344.      * thread's subgroups are also included. If the array is too short to 
  345.      * hold all the threads, the extra threads are silently ignored. 
  346.      * <p>
  347.      * First, the <code>checkAccess</code> method of this thread group is 
  348.      * called with no arguments; this may result in a security exception. 
  349.      * <p>
  350.      * An application should use the <code>activeCount</code> method to 
  351.      * get an estimate of how big the array should be. 
  352.      *
  353.      * @param   list      an array into which to place the list of threads.
  354.      * @param   recurse   a flag indicating whether also to include threads
  355.      *                    in thread groups that are subgroups of this
  356.      *                    thread group.
  357.      * @return  the number of threads placed into the array.
  358.      * @exception  SecurityException  if the current thread does not
  359.      *               have permission to enumerate this thread group.
  360.      * @see     java.lang.ThreadGroup#activeCount()
  361.      * @see     java.lang.ThreadGroup#checkAccess()
  362.      * @since   JDK1.0
  363.      */
  364.     public int enumerate(Thread list[], boolean recurse) {
  365.         checkAccess();
  366.     return enumerate(list, 0, recurse);
  367.     }
  368.  
  369.     private int enumerate(Thread list[], int n, boolean recurse) {
  370.     int ngroupsSnapshot = 0;
  371.     ThreadGroup[] groupsSnapshot = null;
  372.     synchronized (this) {
  373.         if (destroyed) {
  374.         return 0;
  375.         }
  376.         int nt = nthreads;
  377.         if (nt > list.length - n) {
  378.         nt = list.length - n;
  379.         }
  380.         for (int i = 0; i < nt; i++) {
  381.                 if (threads[i].isAlive()) {
  382.                     list[n++] = threads[i];
  383.                 }
  384.             }
  385.         if (recurse) {
  386.         ngroupsSnapshot = ngroups;
  387.         if (groups != null) {
  388.             groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  389.             System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  390.         } else {
  391.             groupsSnapshot = null;
  392.         }
  393.         }
  394.     }
  395.     if (recurse) {
  396.         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  397.         n = groupsSnapshot[i].enumerate(list, n, true);
  398.         }
  399.     }
  400.     return n;
  401.     }
  402.  
  403.     /**
  404.      * Returns an estimate of the number of active groups in this
  405.      * thread group.
  406.      *
  407.      * @return  the number of active thread groups with this thread group as
  408.      *          an ancestor.
  409.      * @since   JDK1.0
  410.      */
  411.     public int activeGroupCount() {
  412.     int ngroupsSnapshot;
  413.     ThreadGroup[] groupsSnapshot;
  414.     synchronized (this) {
  415.         if (destroyed) {
  416.         return 0;
  417.         }
  418.         ngroupsSnapshot = ngroups;
  419.         if (groups != null) {
  420.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  421.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  422.         } else {
  423.         groupsSnapshot = null;
  424.         }
  425.     }
  426.     int n = ngroupsSnapshot;
  427.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  428.         n += groupsSnapshot[i].activeGroupCount();
  429.     }
  430.     return n;
  431.     }
  432.  
  433.     /**
  434.      * Copies into the specified array references to every active 
  435.      * subgroup in this thread group. 
  436.      * <p>
  437.      * First, the <code>checkAccess</code> method of this thread group is 
  438.      * called with no arguments; this may result in a security exception. 
  439.      * <p>
  440.      * An application should use the <code>activeGroupCount</code> 
  441.      * method to get an estimate of how big the array should be. If the 
  442.      * array is too short to hold all the thread groups, the extra thread 
  443.      * groups are silently ignored. 
  444.      *
  445.      * @param   list   an array into which to place the list of thread groups.
  446.      * @return  the number of thread groups put into the array.
  447.      * @exception  SecurityException  if the current thread does not
  448.      *               have permission to enumerate this thread group.
  449.      * @see     java.lang.ThreadGroup#activeGroupCount()
  450.      * @see     java.lang.ThreadGroup#checkAccess()
  451.      * @since   JDK1.0
  452.      */
  453.     public int enumerate(ThreadGroup list[]) {
  454.         checkAccess();
  455.     return enumerate(list, 0, true);
  456.     }
  457.  
  458.     /**
  459.      * Copies into the specified array references to every active 
  460.      * subgroup in this thread group. If the <code>recurse</code> flag is 
  461.      * <code>true</code>, references to all active subgroups of the 
  462.      * subgroups and so forth are also included. 
  463.      * <p>
  464.      * First, the <code>checkAccess</code> method of this thread group is 
  465.      * called with no arguments; this may result in a security exception. 
  466.      * <p>
  467.      * An application should use the <code>activeGroupCount</code> 
  468.      * method to get an estimate of how big the array should be. 
  469.      *
  470.      * @param   list      an array into which to place the list of threads.
  471.      * @param   recurse   a flag indicating whether to recursively enumerate
  472.      *                    all included thread groups.
  473.      * @return  the number of thread groups put into the array.
  474.      * @exception  SecurityException  if the current thread does not
  475.      *               have permission to enumerate this thread group.
  476.      * @see     java.lang.ThreadGroup#activeGroupCount()
  477.      * @see     java.lang.ThreadGroup#checkAccess()
  478.      * @since   JDK1.0
  479.      */
  480.     public int enumerate(ThreadGroup list[], boolean recurse) {
  481.         checkAccess();
  482.     return enumerate(list, 0, recurse);
  483.     }
  484.  
  485.     private int enumerate(ThreadGroup list[], int n, boolean recurse) {
  486.     int ngroupsSnapshot = 0;
  487.     ThreadGroup[] groupsSnapshot = null;
  488.     synchronized (this) {
  489.         if (destroyed) {
  490.         return 0;
  491.         }
  492.         int ng = ngroups;
  493.         if (ng > list.length - n) {
  494.         ng = list.length - n;
  495.         }
  496.         if (ng > 0) {
  497.         System.arraycopy(groups, 0, list, n, ng);
  498.         n += ng;
  499.         }
  500.         if (recurse) {
  501.         ngroupsSnapshot = ngroups;
  502.         if (groups != null) {
  503.             groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  504.             System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  505.         } else {
  506.             groupsSnapshot = null;
  507.         }
  508.         }
  509.     }
  510.     if (recurse) {
  511.         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  512.         n = groupsSnapshot[i].enumerate(list, n, true);
  513.         }
  514.     }
  515.     return n;
  516.     }
  517.  
  518.     /**
  519.      * Stops all threads in this thread group.
  520.      * <p>
  521.      * First, the <code>checkAccess</code> method of this thread group is 
  522.      * called with no arguments; this may result in a security exception. 
  523.      * <p>
  524.      * This method then calls the <code>stop</code> method on all the 
  525.      * threads in this thread group and in all of its subgroups. 
  526.      *
  527.      * @exception  SecurityException  if the current thread is not allowed
  528.      *               to access this thread group or any of the threads in
  529.      *               the thread group.
  530.      * @see        java.lang.SecurityException
  531.      * @see        java.lang.Thread#stop()
  532.      * @see        java.lang.ThreadGroup#checkAccess()
  533.      * @since      JDK1.0
  534.      * @deprecated    This method is inherently unsafe.  See
  535.      *     {@link Thread#stop} for details.
  536.      */
  537.     public final void stop() {
  538.     int ngroupsSnapshot;
  539.     ThreadGroup[] groupsSnapshot;
  540.     synchronized (this) {
  541.         checkAccess();
  542.         for (int i = 0 ; i < nthreads ; i++) {
  543.         threads[i].stop();
  544.         }
  545.         ngroupsSnapshot = ngroups;
  546.         if (groups != null) {
  547.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  548.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  549.         } else {
  550.         groupsSnapshot = null;
  551.         }
  552.     }
  553.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  554.         groupsSnapshot[i].stop();
  555.     }
  556.     }
  557.  
  558.     /**
  559.      * Interrupts all threads in this thread group.
  560.      * <p>
  561.      * First, the <code>checkAccess</code> method of this thread group is 
  562.      * called with no arguments; this may result in a security exception. 
  563.      * <p>
  564.      * This method then calls the <code>interrupt</code> method on all the 
  565.      * threads in this thread group and in all of its subgroups.
  566.      *
  567.      * @exception  SecurityException  if the current thread is not allowed
  568.      *               to access this thread group or any of the threads in
  569.      *               the thread group.
  570.      * @see        java.lang.Thread#interrupt()
  571.      * @see        java.lang.SecurityException
  572.      * @see        java.lang.ThreadGroup#checkAccess()
  573.      * @since      JDK1.2
  574.      */
  575.     public final void interrupt() {
  576.     int ngroupsSnapshot;
  577.     ThreadGroup[] groupsSnapshot;
  578.     synchronized (this) {
  579.         checkAccess();
  580.         for (int i = 0 ; i < nthreads ; i++) {
  581.         threads[i].interrupt();
  582.         }
  583.         ngroupsSnapshot = ngroups;
  584.         if (groups != null) {
  585.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  586.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  587.         } else {
  588.         groupsSnapshot = null;
  589.         }
  590.     }
  591.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  592.         groupsSnapshot[i].interrupt();
  593.     }
  594.     }
  595.  
  596.     /**
  597.      * Suspends all threads in this thread group.
  598.      * <p>
  599.      * First, the <code>checkAccess</code> method of this thread group is 
  600.      * called with no arguments; this may result in a security exception. 
  601.      * <p>
  602.      * This method then calls the <code>suspend</code> method on all the 
  603.      * threads in this thread group and in all of its subgroups. 
  604.      *
  605.      * @exception  SecurityException  if the current thread is not allowed
  606.      *               to access this thread group or any of the threads in
  607.      *               the thread group.
  608.      * @see        java.lang.Thread#suspend()
  609.      * @see        java.lang.SecurityException
  610.      * @see        java.lang.ThreadGroup#checkAccess()
  611.      * @since      JDK1.0
  612.      * @deprecated    This method is inherently deadlock-prone.  See
  613.      *     {@link Thread#suspend} for details.
  614.      */
  615.     public final void suspend() {
  616.     int ngroupsSnapshot;
  617.     ThreadGroup[] groupsSnapshot;
  618.     synchronized (this) {
  619.         checkAccess();
  620.         for (int i = 0 ; i < nthreads ; i++) {
  621.         threads[i].suspend();
  622.         }
  623.         ngroupsSnapshot = ngroups;
  624.         if (groups != null) {
  625.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  626.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  627.         } else {
  628.         groupsSnapshot = null;
  629.         }
  630.     }
  631.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  632.         groupsSnapshot[i].suspend();
  633.     }
  634.     }
  635.  
  636.     /**
  637.      * Resumes all threads in this thread group.
  638.      * <p>
  639.      * First, the <code>checkAccess</code> method of this thread group is 
  640.      * called with no arguments; this may result in a security exception. 
  641.      * <p>
  642.      * This method then calls the <code>resume</code> method on all the 
  643.      * threads in this thread group and in all of its sub groups. 
  644.      *
  645.      * @exception  SecurityException  if the current thread is not allowed to
  646.      *               access this thread group or any of the threads in the
  647.      *               thread group.
  648.      * @see        java.lang.SecurityException
  649.      * @see        java.lang.Thread#resume()
  650.      * @see        java.lang.ThreadGroup#checkAccess()
  651.      * @since      JDK1.0
  652.      * @deprecated    This method is used solely in conjunction with
  653.      *      <tt>Thread.suspend</tt> and <tt>ThreadGroup.suspend</tt>,
  654.      *       both of which have been deprecated, as they are inherently
  655.      *       deadlock-prone.  See {@link Thread#suspend} for details.
  656.      */
  657.     public final void resume() {
  658.     int ngroupsSnapshot;
  659.     ThreadGroup[] groupsSnapshot;
  660.     synchronized (this) {
  661.         checkAccess();
  662.         for (int i = 0 ; i < nthreads ; i++) {
  663.         threads[i].resume();
  664.         }
  665.         ngroupsSnapshot = ngroups;
  666.         if (groups != null) {
  667.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  668.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  669.         } else {
  670.         groupsSnapshot = null;
  671.         }
  672.     }
  673.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  674.         groupsSnapshot[i].resume();
  675.     }
  676.     }
  677.  
  678.     /**
  679.      * Destroys this thread group and all of its subgroups. This thread 
  680.      * group must be empty, indicating that all threads that had been in 
  681.      * this thread group have since stopped. 
  682.      * <p>
  683.      * First, the <code>checkAccess</code> method of this thread group is 
  684.      * called with no arguments; this may result in a security exception. 
  685.      *
  686.      * @exception  IllegalThreadStateException  if the thread group is not
  687.      *               empty or if the thread group has already been destroyed.
  688.      * @exception  SecurityException  if the current thread cannot modify this
  689.      *               thread group.
  690.      * @see        java.lang.ThreadGroup#checkAccess()
  691.      * @since      JDK1.0
  692.      */
  693.     public final void destroy() {
  694.     int ngroupsSnapshot;
  695.     ThreadGroup[] groupsSnapshot;
  696.     synchronized (this) {
  697.         checkAccess();
  698.         if (destroyed || (nthreads > 0)) {
  699.         throw new IllegalThreadStateException();
  700.         }
  701.         ngroupsSnapshot = ngroups;
  702.         if (groups != null) {
  703.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  704.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  705.         } else {
  706.         groupsSnapshot = null;
  707.         }
  708.         if (parent != null) {
  709.         destroyed = true;
  710.         ngroups = 0;
  711.         groups = null;
  712.         nthreads = 0;
  713.         threads = null;
  714.         }
  715.     }
  716.     for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
  717.         groupsSnapshot[i].destroy();
  718.     }
  719.     if (parent != null) {
  720.         parent.remove(this);
  721.     }
  722.     }
  723.  
  724.     /**
  725.      * Adds the specified Thread group to this group.
  726.      * @param g the specified Thread group to be added
  727.      * @exception IllegalThreadStateException If the Thread group has been destroyed.
  728.      */
  729.     private final void add(ThreadGroup g){
  730.     synchronized (this) {
  731.         if (destroyed) {
  732.         throw new IllegalThreadStateException();
  733.         }
  734.         if (groups == null) {
  735.         groups = new ThreadGroup[4];
  736.         } else if (ngroups == groups.length) {
  737.         ThreadGroup newgroups[] = new ThreadGroup[ngroups * 2];
  738.         System.arraycopy(groups, 0, newgroups, 0, ngroups);
  739.         groups = newgroups;
  740.         }
  741.         groups[ngroups] = g;
  742.  
  743.         // This is done last so it doesn't matter in case the
  744.         // thread is killed
  745.         ngroups++;
  746.     }
  747.     }
  748.  
  749.     /**
  750.      * Removes the specified Thread group from this group.
  751.      * @param g the Thread group to be removed
  752.      * @return if this Thread has already been destroyed.
  753.      */
  754.     private void remove(ThreadGroup g) {
  755.     synchronized (this) {
  756.         if (destroyed) {
  757.         return;
  758.         }
  759.         for (int i = 0 ; i < ngroups ; i++) {
  760.         if (groups[i] == g) {
  761.             ngroups -= 1;
  762.             System.arraycopy(groups, i + 1, groups, i, ngroups - i);
  763.             // Zap dangling reference to the dead group so that
  764.             // the garbage collector will collect it.
  765.             groups[ngroups] = null;
  766.             break;
  767.         }
  768.         }
  769.         if (nthreads == 0) {
  770.         notifyAll();
  771.         }
  772.         if (daemon && (nthreads == 0) && (ngroups == 0)) {
  773.         destroy();
  774.         }
  775.     }
  776.     }
  777.     
  778.     /**
  779.      * Adds the specified Thread to this group.
  780.      * @param t the Thread to be added
  781.      * @exception IllegalThreadStateException If the Thread group has been destroyed.
  782.      */
  783.     void add(Thread t) {
  784.     synchronized (this) {
  785.         if (destroyed) {
  786.         throw new IllegalThreadStateException();
  787.         }
  788.         if (threads == null) {
  789.         threads = new Thread[4];
  790.         } else if (nthreads == threads.length) {
  791.         Thread newthreads[] = new Thread[nthreads * 2];
  792.         System.arraycopy(threads, 0, newthreads, 0, nthreads);
  793.         threads = newthreads;
  794.         }
  795.         threads[nthreads] = t;
  796.  
  797.         // This is done last so it doesn't matter in case the
  798.         // thread is killed
  799.         nthreads++;
  800.     }
  801.     }
  802.  
  803.     /**
  804.      * Removes the specified Thread from this group.
  805.      * @param t the Thread to be removed
  806.      * @return if the Thread has already been destroyed.
  807.      */
  808.     void remove(Thread t) {
  809.     synchronized (this) {
  810.         if (destroyed) {
  811.         return;
  812.         }
  813.         for (int i = 0 ; i < nthreads ; i++) {
  814.         if (threads[i] == t) {
  815.             System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
  816.             // Zap dangling reference to the dead thread so that
  817.             // the garbage collector will collect it.
  818.             threads[nthreads] = null;
  819.             break;
  820.         }
  821.         }
  822.         if (nthreads == 0) {
  823.         notifyAll();
  824.         }
  825.         if (daemon && (nthreads == 0) && (ngroups == 0)) {
  826.         destroy();
  827.         }
  828.     }
  829.     }
  830.  
  831.     /**
  832.      * Prints information about this thread group to the standard 
  833.      * output. This method is useful only for debugging. 
  834.      *
  835.      * @since   JDK1.0
  836.      */
  837.     public void list() {
  838.     list(System.out, 0);
  839.     }
  840.     void list(PrintStream out, int indent) {
  841.     int ngroupsSnapshot;
  842.     ThreadGroup[] groupsSnapshot;
  843.     synchronized (this) {
  844.         for (int j = 0 ; j < indent ; j++) {
  845.         out.print(" ");
  846.         }
  847.         out.println(this);
  848.         indent += 4;
  849.         for (int i = 0 ; i < nthreads ; i++) {
  850.         for (int j = 0 ; j < indent ; j++) {
  851.             out.print(" ");
  852.         }
  853.         out.println(threads[i]);
  854.         }
  855.         ngroupsSnapshot = ngroups;
  856.         if (groups != null) {
  857.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  858.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  859.         } else {
  860.         groupsSnapshot = null;
  861.         }
  862.     }
  863.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  864.         groupsSnapshot[i].list(out, indent);
  865.     }
  866.     }
  867.  
  868.     /**
  869.      * Called by the Java Virtual Machine when a thread in this 
  870.      * thread group stops because of an uncaught exception. 
  871.      * <p>
  872.      * The <code>uncaughtException</code> method of 
  873.      * <code>ThreadGroup</code> does the following: 
  874.      * <ul>
  875.      * <li>If this thread group has a parent thread group, the
  876.      *     <code>uncaughtException</code> method of that parent is called
  877.      *     with the same two arguments. 
  878.      * <li>Otherwise, this method determines if the <code>Throwable</code>
  879.      *     argument is an instance of <code>ThreadDeath</code>. If so, nothing
  880.      *     special is done. Otherwise, the <code>Throwable</code>'s
  881.      *     <code>printStackTrace</code> method is called to print a stack
  882.      *     backtrace to the standard error stream.
  883.      * </ul>
  884.      * <p>
  885.      * Applications can override this method in subclasses of 
  886.      * <code>ThreadGroup</code> to provide alternative handling of 
  887.      * uncaught exceptions. 
  888.      *
  889.      * @param   t   the thread that is about to exit.
  890.      * @param   e   the uncaught exception.
  891.      * @see     java.lang.System#err
  892.      * @see     java.lang.ThreadDeath
  893.      * @see     java.lang.Throwable#printStackTrace(java.io.PrintStream)
  894.      * @since   JDK1.0
  895.      */
  896.     public void uncaughtException(Thread t, Throwable e) {
  897.     if (parent != null) {
  898.         parent.uncaughtException(t, e);
  899.     } else if (!(e instanceof ThreadDeath)) {
  900.         e.printStackTrace(System.err);
  901.     }
  902.     }
  903.  
  904.     /**
  905.      * Used by VM to control lowmem implicit suspension.
  906.      *
  907.      * @since   JDK1.1
  908.      * @deprecated The definition of this call depends on {@link #suspend},
  909.      *           which is deprecated.  Further, the behavior of this call
  910.      *           was never specified.
  911.      */
  912.     public boolean allowThreadSuspension(boolean b) {
  913.     this.vmAllowSuspension = b;
  914.     if (!b) {
  915.         VM.unsuspendSomeThreads();
  916.     }
  917.     return true;
  918.     }
  919.  
  920.     /**
  921.      * Returns a string representation of this Thread group.
  922.      *
  923.      * @return  a string representation of this thread group.
  924.      * @since   JDK1.0
  925.      */
  926.     public String toString() {
  927.     return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
  928.     }
  929. }
  930.